local lu = require 'luaunit'
local c_psu_object = require 'device.psu'
local c_power_configuration = require 'device.power_configuration'
local c_psu_service = require 'psu_service'
local client = require 'power_mgmt.client'
local c_efficiency_curve_object = require 'efficiency_curve'
local custom_msg = require 'messages.custom'
local base_msg = require 'messages.base'
local psu_service = require 'psu_service'
local RET_OK <const> = 0
local RET_ERR <const> = -1

local common_ret = RET_ERR

TestPsu = {}

function TestPsu:test_psu_firmware_register()
    function client:PFirmwareInventoryFirmwareInventoryAdd(ctx, FirmwareInfoTable, ...)
        if FirmwareInfoTable.Id == 'EXU_PSU1' then
            common_ret = RET_OK
        end
    end

    c_psu_object.DeviceLocator = 'PowerConverter1'
    c_psu_object.Position = 'EXU'
    c_psu_object.Model = 'qb900'
    c_psu_object.Manufacturer = 'huawei'
    c_psu_object:register_fw_info()
    lu.assertEquals(common_ret, RET_OK)
end

function TestPsu:test_psu_power_level()
    c_psu_object.position = "01010B"
    c_psu_object.PartNumber = "02313FNC"
    c_psu_object.PowerLevel = "N/A"
    c_efficiency_curve_object.collection.fold = function(...)
        if c_psu_object.position == "010109" and c_psu_object.PartNumber == "02313FNC" then
            c_psu_object.PowerLevel = "80PLUS Platinum"
        end
    end
    c_psu_object.update_power_level(c_psu_object)
    lu.assertEquals(c_psu_object.PowerLevel, "N/A")

    c_psu_object.position = "010109"
    c_efficiency_curve_object.collection.fold = function(...)
        if c_psu_object.position == "010109" and c_psu_object.PartNumber == "02313FNC" then
            c_psu_object.PowerLevel = "80PLUS Platinum"
        end
    end
    c_psu_object.update_power_level(c_psu_object)
    lu.assertEquals(c_psu_object.PowerLevel, "80PLUS Platinum")
    
    c_psu_object.PowerLevel = "80PLUS"
    c_psu_object.update_power_level(c_psu_object)
    lu.assertEquals(c_psu_object.PowerLevel, "80PLUS")
end

function TestPsu:test_update_efficiency_curve()
    c_psu_object.position = "010109"
    c_psu_object.PartNumber = "02313FNC"
    c_psu_object.InputVoltage = 220
    c_psu_object.PowerLevel = "80PLUS Platinum"
    c_efficiency_curve_object.collection.find = function(...)
           return { PowerLevel = "80PLUS Platinum" }
        end
    c_psu_object.update_efficiency_curve(c_psu_object)
    lu.assertEquals(c_psu_object.PowerLevel, "80PLUS Platinum")
end

function TestPsu:test_is_attribute_mismatch()
    local power_mgmt_app = require "power_mgmt_app"
    lu.assertEquals(power_mgmt_app ~= nil, true)
    c_psu_object.power_mgmt_instance = require 'device.power_mgmt'.new()
    local obj = {
        ["IsManufacturerMismatch"] = false,
        ["IsModelMismatch"] = false
    }
    c_psu_object.power_mgmt_instance:set_obj(obj)
    c_psu_object.power_mgmt_instance:set_value("IsManufacturerMismatch", false)
    c_psu_object.Manufacturer = "Huawei"
    ans = c_psu_object.is_attribute_mismatch(c_psu_object, "Manufacturer")
    c_psu_object.is_mismatch(c_psu_object)
    lu.assertEquals(ans, false)
    c_psu_object.power_mgmt_instance:set_obj(nil)
end

function TestPsu:test_set_psu_fan_rpm_2()
    c_psu_object.Cooling = {}
    c_psu_object.Cooling.methods = {}
    c_psu_object.Cooling.methods.SetFanRPM = function ()
        error('set failed')
    end
    local res = pcall(function ()
        return c_psu_object.set_psu_fan_rpm(c_psu_object)
    end)
    lu.assertEquals(res, true)
end

function TestPsu:test_get_psu_fan_rpm_1()
    c_psu_object.Cooling = {}
    c_psu_object.Cooling.methods = {}
    c_psu_object.Cooling.methods.GetFanRPM = function ()
        return 10
    end
    local res = c_psu_object.get_psu_fan_rpm(c_psu_object)
    lu.assertEquals(res, 10)
end

function TestPsu:test_get_psu_fan_rpm_2()
    c_psu_object.Cooling = {}
    c_psu_object.Cooling.methods = {}
    c_psu_object.Cooling.methods.GetFanRPM = function ()
        error('get failed')
    end
    local res = pcall(function ()
        return c_psu_object.get_psu_fan_rpm(c_psu_object)
    end)
    lu.assertEquals(res, false)
end

function TestPsu:test_get_psu_register_info_1()
    c_psu_object.Power = {}
    c_psu_object.Power.methods = {}
    c_psu_object.Power.methods.GetPsuRegisterInfo = function ()
        return 10
    end
    local res = c_psu_object.get_psu_register_info(c_psu_object)
    lu.assertEquals(res, 10)
end

function TestPsu:test_get_psu_register_info_2()
    c_psu_object.Power = {}
    c_psu_object.Power.methods = {}
    c_psu_object.Power.methods.GetPsuRegisterInfo = function ()
        error('get failed')
    end
    local res, rsp = pcall(function ()
        return c_psu_object.get_psu_register_info(c_psu_object)
    end)
    lu.assertEquals(res, false)
    lu.assertEquals(rsp, custom_msg.OperationFailed())
end

function TestPsu:test_update_firmware()
    function c_psu_object.update_firmware_info(c_psu_object)
        return true
    end
    c_psu_object.ps_id = 1
    c_psu_object.last_firmware_version = "DC:106 PFC:106"
    c_psu_object.FirmwareVersion = "DC:108 PFC:108"
    c_psu_object.update_firmware(c_psu_object)
    lu.assertEquals(c_psu_object.last_firmware_version, "DC:108 PFC:108")
end

function TestPsu:test_update_rate()
    c_psu_object.ps_id = 1
    c_psu_object.last_rate = 2000
    c_psu_object.Rate = 1800
    c_psu_object.last_input_voltage = 220
    c_psu_object.InputVoltage = 180
    c_psu_object.update_rate(c_psu_object)
    lu.assertEquals(c_psu_object.last_rate, 1800)
    lu.assertEquals(c_psu_object.last_input_voltage, 180)
end

function TestPsu:test_set_psu_power_latch_1()
    c_psu_object.Power = {}
    c_psu_object.Power.methods = {}
    c_psu_object.Power.methods.PowerLatch = function ()
        error('set failed')
    end
    local res = pcall(function ()
        return c_psu_object.set_psu_power_latch()
    end)
    lu.assertEquals(res, false)
end

local E_OK <const> = nil -- 函数执行成功返回nil
local E_FAILED <const> = '' -- 空错误信息
function TestPsu:test_set_power_latch()
    c_psu_object.collection.fold = function (...)
        error('set failed')
    end
    local ok = pcall(function ()
        psu_service:set_power_latch()
    end)
    lu.assertEquals(ok, false)
end

function TestPsu:test_get_upgrade_channel_1()
    c_psu_object.Upgrade = {}
    c_psu_object.Upgrade.methods = {}
    c_psu_object.Upgrade.methods.GetUpgradeChannel = function ()
        error('set failed')
    end
    local res = pcall(function ()
        return c_psu_object.get_upgrade_channel()
    end)
    lu.assertEquals(res, false)
end

function TestPsu:test_get_upgrade_channel_2()
    c_psu_object.Upgrade = {}
    c_psu_object.Upgrade.methods = {}
    c_psu_object.Upgrade.methods.GetUpgradeChannel = function ()
        return 1
    end
    local res = c_psu_object.get_upgrade_channel(c_psu_object)
    lu.assertEquals(res, 1)
end

function TestPsu:test_get_upgrade_channel_3()
    c_psu_object.Upgrade = {}
    c_psu_object.Upgrade.methods = {}
    c_psu_object.Upgrade.methods.GetUpgradeChannel = nil
    local res = c_psu_object.get_upgrade_channel(c_psu_object)
    lu.assertEquals(res, E_FAILED)
end

function TestPsu:test_change_polling_channel_1()
    c_psu_object.Upgrade = {}
    c_psu_object.Upgrade.methods = {}
    c_psu_object.Upgrade.methods.ChangePollingChannel = function ()
        error('set failed')
    end
    local res = pcall(function ()
        return c_psu_object.change_polling_channel()
    end)
    lu.assertEquals(res, false)
end

function TestPsu:test_change_polling_channel_2()
    c_psu_object.Upgrade = {}
    c_psu_object.Upgrade.methods = {}
    c_psu_object.Upgrade.methods.ChangePollingChannel = function ()
        return E_OK
    end
    local res = c_psu_object.change_polling_channel(c_psu_object)
    lu.assertEquals(res, E_OK)
end

function TestPsu:test_change_polling_channel_3()
    c_psu_object.Upgrade = {}
    c_psu_object.Upgrade.methods = {}
    c_psu_object.Upgrade.methods.ChangePollingChannel = nil
    local res = c_psu_object.change_polling_channel(c_psu_object)
    lu.assertEquals(res, E_FAILED)
end

function TestPsu:test_recover_polling_channel_1()
    c_psu_object.Upgrade = {}
    c_psu_object.Upgrade.methods = {}
    c_psu_object.Upgrade.methods.RecoverPollingChannel = function ()
        error('set failed')
    end
    local res = pcall(function ()
        return c_psu_object.recover_polling_channel()
    end)
    lu.assertEquals(res, false)
end

function TestPsu:test_recover_polling_channel_2()
    c_psu_object.Upgrade = {}
    c_psu_object.Upgrade.methods = {}
    c_psu_object.Upgrade.methods.RecoverPollingChannel = function ()
        return E_OK
    end
    local res = c_psu_object.recover_polling_channel(c_psu_object)
    lu.assertEquals(res, E_OK)
end

function TestPsu:test_recover_polling_channel_3()
    c_psu_object.Upgrade = {}
    c_psu_object.Upgrade.methods = {}
    c_psu_object.Upgrade.methods.RecoverPollingChannel = nil
    local res = c_psu_object.recover_polling_channel(c_psu_object)
    lu.assertEquals(res, E_FAILED)
end

function TestPsu:test_set_power_capacitor_enable_1()
    c_psu_object.Power = {}
    c_psu_object.Power.methods = {}
    c_psu_object.Power.methods.SetPowerCapacitorEnable = nil
    local res = c_psu_object.set_power_capacitor_enable(c_psu_object)
    lu.assertEquals(res, E_FAILED)
end

function TestPsu:test_set_power_capacitor_enable_2()
    c_psu_object.Power = {}
    c_psu_object.Power.methods = {}
    c_psu_object.Power.methods.SetPowerCapacitorEnable = function (...)
        return E_OK
    end
    local res = c_psu_object.set_power_capacitor_enable(c_psu_object)
    lu.assertEquals(res, E_OK)
end

function TestPsu:test_set_power_capacitor_enable_3()
    c_psu_object.Upgrade = {}
    c_psu_object.Upgrade.methods = {}
    c_psu_object.Upgrade.methods.SetPowerCapacitorEnable = function ()
        error('set failed')
    end
    local res = pcall(function ()
        return c_psu_object.set_power_capacitor_enable()
    end)
    lu.assertEquals(res, false)
end

function TestPsu:test_psu_service_set_power_capacitor_1()
    c_psu_object.collection.find = function (...)
        return nil
    end
    local ok = pcall(function ()
        psu_service:set_power_capacitor_enable(c_psu_object, 'enable')
    end)
    lu.assertEquals(ok, true)
end


function TestPsu:test_psu_service_set_power_capacitor_2()
    local psu_obj = {}
    psu_obj.set_power_capacitor_enable = function (...)
        return E_OK
    end
    c_psu_object.collection.find = function (...)
        return psu_obj
    end

    local ok, err = pcall(function ()
        return psu_service:set_power_capacitor_enable(c_psu_object, 'enable')
    end)
    lu.assertEquals(ok, true)
    lu.assertEquals(err, E_OK)
end

function TestPsu:test_set_power_capacitor_calibrate()
    local c_psu_object_mock = {
        Power = {
            methods = {
                SetPowerCapacitorCalibrate = function ()
                    return base_msg.ActionNotSupported()
                end
            }
        }
    }
    local ok, rsp = pcall(function ()
        return c_psu_object.set_power_capacitor_calibrate(c_psu_object_mock)
    end)
    lu.assertTrue(ok)
    lu.assertEquals(rsp.name, base_msg.ActionNotSupportedMessage.Name)

    c_psu_object_mock.Power.methods.SetPowerCapacitorCalibrate = function ()
        return nil
    end
    ok, rsp = pcall(function ()
        return c_psu_object.set_power_capacitor_calibrate(c_psu_object_mock)
    end)
    lu.assertTrue(ok)
    lu.assertEquals(rsp, nil)
end

function TestPsu:test_get_power_capacitor_calibrate_time()
    local c_psu_object_mock = {
        Power = {
            methods = {
                GetPowerCapacitorCalibrateTime = function ()
                    return base_msg.ActionNotSupported()
                end
            }
        }
    }
    local ok, rsp = pcall(function ()
        return c_psu_object.get_power_capacitor_calibrate_time(c_psu_object_mock)
    end)
    lu.assertTrue(ok)
    lu.assertEquals(rsp.name, base_msg.ActionNotSupportedMessage.Name)

    c_psu_object_mock.Power.methods.GetPowerCapacitorCalibrateTime = function ()
        return nil
    end
    ok, rsp = pcall(function ()
        return c_psu_object.get_power_capacitor_calibrate_time(c_psu_object_mock)
    end)
    lu.assertTrue(ok)
    lu.assertEquals(rsp, nil)
end

function TestPsu:test_get_power_capacitor_calibrate()
    local c_psu_object_mock = {
        Power = {
            methods = {
                GetPowerCapacitorCalibrate = function ()
                    return base_msg.ActionNotSupported()
                end
            }
        }
    }
    local ok, rsp = pcall(function ()
        return c_psu_object.get_power_capacitor_calibrate(c_psu_object_mock)
    end)
    lu.assertTrue(ok)
    lu.assertEquals(rsp.name, base_msg.ActionNotSupportedMessage.Name)

    c_psu_object_mock.Power.methods.GetPowerCapacitorCalibrate = function ()
        return nil
    end
    ok, rsp = pcall(function ()
        return c_psu_object.get_power_capacitor_calibrate(c_psu_object_mock)
    end)
    lu.assertTrue(ok)
    lu.assertEquals(rsp, nil)
end


function TestPsu:test_set_retransfer_delay_seconds()
    local c_psu_object_mock = {
        Power = {
            methods = {
                SetRetransferDelaySeconds = function ()
                    return base_msg.ActionNotSupported()
                end
            }
        }
    }
    local ok, rsp = pcall(function ()
        return c_psu_object.set_retransfer_delay_seconds(c_psu_object_mock)
    end)
    lu.assertTrue(ok)
    lu.assertEquals(rsp, nil)

    c_psu_object_mock.Power.methods.SetRetransferDelaySeconds = function ()
        error('set failed')
    end
    local res = pcall(function ()
        return c_psu_object.set_retransfer_delay_seconds(c_psu_object_mock)
    end)
    lu.assertEquals(res, true)
end

function TestPsu:test_min_allowed_psu_count_check()
    local tab = {MinAvailablePSUCountForUpgrade = nil}
    local res = c_power_configuration.get_min_allowed_psu_count(tab, 2)
    lu.assertEquals(res, 1)

    local tab1 = {MinAvailablePSUCountForUpgrade = 10}
    local res1 = c_power_configuration.get_min_allowed_psu_count(tab1, 2)
    lu.assertEquals(res1, 10)
end

function TestPsu:test_get_retransfer_delay_seconds()
    local c_psu_object_mock = {
        Power = {
            methods = {
                GetRetransferDelaySeconds = function ()
                    return base_msg.ActionNotSupported()
                end
            }
        }
    }
    local ok, rsp = pcall(function ()
        return c_psu_object.get_retransfer_delay_seconds(c_psu_object_mock)
    end)
    lu.assertTrue(ok)
    lu.assertEquals(rsp.name, base_msg.ActionNotSupportedMessage.Name)

    c_psu_object_mock.Power.methods.GetRetransferDelaySeconds = function ()
        error('set failed')
    end
    local res = pcall(function ()
        return c_psu_object.get_retransfer_delay_seconds(c_psu_object_mock)
    end)
    lu.assertEquals(res, false)
end

function TestPsu:test_ps_num_exclude_ps_check()
    local tab = {psu_slot = {1,2,3}}
    local psu_objs = {}
    local res = c_psu_service.check_ps_num_exclude_ps(tab, psu_objs)
    lu.assertEquals(res, false)
end

function TestPsu:test_power_upgrade_check()
    local psu_objs = {}
    c_psu_object.position = "010109"
    c_psu_object.PartNumber = "02313FNC"
    c_psu_object.InputVoltage = 220
    c_psu_object.PowerLevel = "80PLUS Platinum"
    c_efficiency_curve_object.collection.find = function(...)
           return { PowerLevel = "80PLUS Platinum" }
        end
    c_psu_object.update_efficiency_curve(c_psu_object)
    local res = c_psu_object.power_upgrade(c_psu_object, '', 1 , psu_objs)
    lu.assertEquals(res, 201)
end